// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <cantor/proto/parser/ast.pb.h>
#include <cantor/common/type_list.h>
#include <cantor/unresolved/stmts/select_stmt.h>
#include <cantor/unresolved/stmts/start_txn_stmt.h>
#include <cantor/unresolved/stmts/commit_txn_stmt.h>
#include <cantor/unresolved/stmts/rollback_txn_stmt.h>
#include <cantor/unresolved/stmts/pragma_set_stmt.h>
#include <cantor/unresolved/stmts/new_prepare_stmt.h>
#include <cantor/unresolved/stmts/exec_prepare_stmt.h>
#include <cantor/unresolved/stmts/dealloc_prepare_stmt.h>
#include <cantor/unresolved/stmts/kill_stmt.h>
#include <cantor/unresolved/stmts/create_namespace_stmt.h>
#include <cantor/unresolved/stmts/drop_namespace_stmt.h>
#include <cantor/unresolved/stmts/alter_namespace_stmt.h>
#include <cantor/unresolved/stmts/create_user_stmt.h>
#include <cantor/unresolved/stmts/drop_user_stmt.h>
#include <cantor/unresolved/stmts/alter_user_stmt.h>
#include <cantor/unresolved/stmts/grant_stmt.h>
#include <cantor/unresolved/stmts/revoke_stmt.h>
#include <cantor/unresolved/stmts/insert_stmt.h>
#include <cantor/unresolved/stmts/update_stmt.h>
#include <cantor/unresolved/stmts/truncate_stmt.h>
#include <cantor/unresolved/stmts/delete_stmt.h>
#include <cantor/unresolved/stmts/union_stmt.h>
#include <cantor/unresolved/stmts/create_table_stmt.h>
#include <cantor/unresolved/stmts/drop_table_stmt.h>
#include <cantor/unresolved/stmts/create_view_stmt.h>
#include <cantor/unresolved/stmts/drop_view_stmt.h>
#include <cantor/unresolved/stmts/create_database_stmt.h>
#include <cantor/unresolved/stmts/alter_table_stmt.h>
#include <cantor/unresolved/stmts/alter_view_stmt.h>
#include <cantor/unresolved/stmts/explain_stmt.h>
#include <cantor/unresolved/stmts/load_data_stmt.h>
#include <cantor/unresolved/stmts/drop_database_stmt.h>
#include <cantor/unresolved/stmts/restore_table_stmt.h>
#include <cantor/unresolved/stmts/type_stmt.h>
///////////////////
///
///


namespace cantor::unresolved {
    template<cantor::pb::ast::StmtType type>
    struct StmtTypeTrait;

    /*
    *
    enum StmtType {
    STMT_RESTORE_TABLE = 29;
    STMT_CREATE_TYPE = 36;
    };*/

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_START_TRANSACTION> {
        using type = UnresolvedStartTxnStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_START_TRANSACTION;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_COMMIT_TRANSACTION> {
        using type = UnresolvedCommitTxnStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_COMMIT_TRANSACTION;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ROLLBACK_TRANSACTION> {
        using type = UnresolvedRollbackTxnStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_ROLLBACK_TRANSACTION;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };


    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_PRAGMA_SET> {
        using type = UnresolvedPragmaSetStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_PRAGMA_SET;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_NEW_PREPARE> {
        using type = UnresolvedNewPrepareStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_NEW_PREPARE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_EXEC_PREPARE> {
        using type = UnresolvedExecPrepareStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_EXEC_PREPARE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DEALLOC_PREPARE> {
        using type = UnresolvedDeallocPrepareStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DEALLOC_PREPARE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_KILL> {
        using type = UnresolvedKillStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_KILL;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_NAMESPACE> {
        using type = UnresolvedCreateNamespaceStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_CREATE_NAMESPACE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_NAMESPACE> {
        using type = UnresolvedDropNamespaceStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DROP_NAMESPACE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_NAMESPACE> {
        using type = UnresolvedAlterNamespaceStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_ALTER_NAMESPACE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_USER> {
        using type = UnresolvedCreateUserStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_CREATE_USER;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_USER> {
        using type = UnresolvedDropUserStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DROP_USER;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_USER> {
        using type = UnresolvedAlterUserStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_ALTER_USER;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_GRANT> {
        using type = UnresolvedGrantStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_GRANT;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_REVOKE> {
        using type = UnresolvedRevokeStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_REVOKE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_INSERT> {
        using type = UnresolvedInsertStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_INSERT;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_UPDATE> {
        using type = UnresolvedUpdateStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_UPDATE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_TRUNCATE> {
        using type = UnresolvedTruncateStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_TRUNCATE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DELETE> {
        using type = UnresolvedDeleteStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DELETE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_SELECT> {
        using type = UnresolvedSelectStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_SELECT;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_UNION> {
        using type = UnresolvedUnionStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_UNION;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_TABLE> {
        using type = UnresolvedCreateTableStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_CREATE_TABLE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_TABLE> {
        using type = UnresolvedDropTableStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DROP_TABLE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_VIEW> {
        using type = UnresolvedCreateViewStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_CREATE_VIEW;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_VIEW> {
        using type = UnresolvedDropViewStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DROP_VIEW;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_DATABASE> {
        using type = UnresolvedCreateDatabaseStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_CREATE_DATABASE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_DATABASE> {
        using type = UnresolvedDropDatabaseStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_DROP_DATABASE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_TABLE> {
        using type = UnresolvedAlterTableStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_ALTER_TABLE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_VIEW> {
        using type = UnresolvedAlterViewStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_ALTER_VIEW;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_EXPLAIN> {
        using type = UnresolvedExplainStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_EXPLAIN;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_LOAD_DATA> {
        using type = UnresolvedLoadDataStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_LOAD_DATA;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_TYPE_NAME> {
        using type = UnresolvedTypeStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_TYPE_NAME;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    template<>
    struct StmtTypeTrait<cantor::pb::ast::StmtType::STMT_RESTORE_TABLE> {
        using type = UnresolvedRestoreTableStmt;
        static constexpr cantor::pb::ast::StmtType stmt_type = cantor::pb::ast::StmtType::STMT_RESTORE_TABLE;
        static_assert(type::TYPE == stmt_type, "type::TYPE must be equal to stmt_type");
    };

    ////////////////////////////////////////////////////////////////////////////////


    using all_stmt_traits = cantor::common::TypeList<
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_START_TRANSACTION>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_COMMIT_TRANSACTION>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ROLLBACK_TRANSACTION>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_PRAGMA_SET>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_NEW_PREPARE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_EXEC_PREPARE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DEALLOC_PREPARE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_KILL>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_NAMESPACE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_NAMESPACE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_NAMESPACE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_USER>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_USER>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_USER>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_GRANT>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_REVOKE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_INSERT>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_UPDATE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_TRUNCATE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DELETE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_SELECT>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_UNION>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_TABLE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_TABLE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_VIEW>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_VIEW>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_CREATE_DATABASE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_DROP_DATABASE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_TABLE>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_ALTER_VIEW>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_EXPLAIN>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_LOAD_DATA>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_TYPE_NAME>,
        StmtTypeTrait<cantor::pb::ast::StmtType::STMT_RESTORE_TABLE>
    >;

    using AllStmtVisitorType = cantor::common::ExtractList<all_stmt_traits>::type;

    template<typename Visitor>
    struct isInAllStmtList : cantor::common::IsInList<Visitor, AllStmtVisitorType> {
    };
} // namespace cantor::unresolved
